logo

yaohaoyou

春节

2024.8.12 树专题分享

2024-08-08 Views 树上问题 | DP | Codeforces1402字6 min read

T1

原题:CF1399E2 Weights Division (hard version) \color{#ffffff}\text{CF1399E2 Weights Division (hard version) }

CF 2200\color{#ffffff}\text{CF 2200}

题意

给你一棵以 11 为根的香蕉树,每条边有边权 wiw_i 和花费 cic_i

每个叶子节点都有一只 liangbowen,他们都想去 11 节点吃香蕉。

但是 liangbowen 们急着去杀戮,所以需要保证 u is liangbowenw(1,u)lim\sum_\text{u is liangbowen}w(1,u)\le limu is liangbowen\text{u is liangbowen} 当且仅当 uu 是叶子节点,w(x,y)w(x,y) 表示 xxyy 的树上距离。

lubenwei 可以开挂,将 wiwi2w_i \gets \lfloor\dfrac{w_i}{2}\rfloor,吸引网管 cic_i 点注意。

lubenwei 不希望开挂太多导致被网管封号,所以请最小化网管的注意使得 liangbowen 们可以准时杀戮,保证有解。

n105,ci{1,2},1wi106,1lim1016n\le 10^5,c_i\in \{1,2\},1\le w_i\le 10^6,1\le lim \le10^{16}

形式化题意:\tiny\text{形式化题意:}

给出一个结点数量为 nn 的边带权的有根树,树的根结点为 11。你可以进行以下操作。

选定任意一条权值为 wiw_i 的边,使 wiwi2w_i \gets \lfloor \frac{w_i}{2} \rfloor,花费为 cic_ici{1,2}c_i \in \{1, 2\}

你需要回答最小的花费,使得 vleavesw(1,v)S\sum\limits_{v\in leaves}w(1,v)\leq S

Easy Version:ci=1c_i=1

题解

先考虑 Easy Version,由于保证 ci=1c_i=1,所以直接贪心即可。

首先可以用树形 DP 求出删掉当前边的贡献,设 dpidp_i 表示 ii 的子树中有多少个叶子节点,不难得出
dpu={dpsonuleaf1u=leafdp_u = \begin{cases}\sum dp_{son} & u \ne leaf \\ 1 & u=leaf \end{cases}

设一条边的贡献为 sis_i,儿子为 vv,则 si=dpv×(wiwi2)s_i=dp_v \times (w_i-\lfloor \frac{w_i}{2} \rfloor)。将 sis_i 丢进大根堆,每次取出 sis_i 最大的边模拟进行操作即可。

再回到 Hard Version。

错的做法

此时还想贪心就变得非常困难,所以可以思考将答案划分成选择边权花费为 11 的答案 ++ 选择边权花费为 22 的答案。当只选择边权花费为 11 的答案时,可以确定操作的顺序(即 Easy Version),同理,只选择边权花费为 22 的答案也可以提前处理操作顺序。

然后只要枚举要操作花费为 11 的次数,并计算花费为 22 的次数即可。此时的时间复杂度为 O(n2×log2n)O(n^2\times \log_2 n),无法通过此题。

观察性质,发现操作花费为 11 的次数越多,操作花费为 22 的次数就越少。所以可以将计算花费为 22 的次数用双指针优化掉,时间复杂度为 O(n×log2n)O(n \times \log_2 n),记得处理操作全是花费为 1122 的答案。

code\color{white}code

T2

原题:CF1059E Split the Tree\color{#ffffff}\text{CF1059E Split the Tree}

CF 2400\color{#ffffff}\text{CF 2400}

题意

lbw 和 Mathew 正在宿舍打 21 点,但是他把牌摆成了一棵树的形状。

规则就是在树上找一条深度依次递增的链,使得链上扑克牌的点数和 21\le 21。同时还有一种规则叫做五龙,就是当你取得 55 张牌时,游戏就结束了。

但是 lbw 想要练习出千,于是把 21 点变成 LL 点,把 55 龙变成 SS 龙,把扑克牌点数的集合变成自然数集。

lbw 有透视眼,可以提前看到每个节点的牌的点。lbw 用最短的时间秒杀 Mathew,所以希望总局数最少。

请求 lbw 最少选出多少条链可以使得每张牌刚好被拿走一次,且牌数 L\le L,点数和 S\le S,需要判无解。

n105,L105,S1018n\le 10^5,L\le10^5,S\le 10^{18}

形式化题意:\tiny\text{形式化题意:}

给一棵带点权的树,每次选一条深度依次递增的链,链长 L\le L,链上点权和 S\le S。想让每个点当且仅当被覆盖一次,求链数最小值,需要判无解。

题解

显然,当有一个点的点权 >S>S 时就无解,否则有解。

考虑一个贪心结论,对于 uuuu 的儿子 vv显然从 uu 往上能到达的点会比 vv 往上到达的点更高或相同,所以节点 uu 一定会选择剩余步数最多的儿子节点进行转移。

可以先使用树上倍增求出每个节点 uu 能到达的最高祖先,计 upuup_u 表示从 uu 节点最多再往上跳 upuup_u 步。

考虑树形DP

fuf_u 表示将 uu 的子树覆盖完的链的最少条数,gug_u 表示 uu 的子树内剩余的最大步数。

gu=maxv is son of u(gv1)fu=v is son of ufvg_u=\max_\text{v is son of u}(g_v-1) \\ f_u=\sum_\text{v is son of u}f_v

若此时 gu=0g_u=0,说明无法从子树内已有的链往上延申,所以需要开一条新链,即 fu++,gu=upuf_u++,g_u=up_u

否则不需要进行修改。

钦定树的根为 11,则答案为 f1f_1

code\color{white}code

EOF